# 使用全连接神经网络，拟合倒数。

import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt

'''
使用全连接神经网络（也称为多层感知器，MLP）来拟合倒数函数（即输入 x 和输出1/x），我们可以使用Python中的深度学习框架
模型定义：FullyConnectedNN类定义了一个具有两个隐藏层（每层64个神经元）的全连接神经网络。
数据生成：生成了从0.1到10的1000个等间距点作为训练数据，并计算其倒数作为标签。
数据转换：将NumPy数组转换为PyTorch张量。
训练过程：使用均方误差损失函数和Adam优化器训练模型。
模型测试与可视化：在训练后的模型上测试，并可视化真实值和预测值。
请注意，由于倒数函数在接近0时值非常大，而远离0时值非常小，这可能导致训练过程中的数值不稳定性。因此，在实际应用中，可能需要更复杂的网络结构、正则化技术或数据预处理方法来提高模型的性能和稳定性。此外，本示例中为了避免除以零的错误，特意将输入数据的范围限制在了0.1到10之间。
'''

# 定义全连接神经网络模型
class FullyConnectedNN(nn.Module):
    def __init__(self):
        super(FullyConnectedNN, self).__init__()
        self.fc1 = nn.Linear(1, 64)  # 输入层和第一个隐藏层
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(64, 64)  # 第一个隐藏层和第二个隐藏层
        self.fc3 = nn.Linear(64, 1)  # 第二个隐藏层和输出层

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.fc3(x)
        return x


# 生成训练数据
x_train = np.linspace(0.1, 10, 1000).reshape(-1, 1)  # 输入数据，避免x=0导致除以零
y_train = 1.0 / x_train

# 转换为PyTorch张量
x_train_tensor = torch.tensor(x_train, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train, dtype=torch.float32)

# 实例化模型、损失函数和优化器
model = FullyConnectedNN()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
    model.train()
    optimizer.zero_grad()
    outputs = model(x_train_tensor)
    loss = criterion(outputs, y_train_tensor)
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')

# 测试模型（使用训练数据进行测试，实际应用中应使用未见过的数据）
model.eval()
with torch.no_grad():
    x_test = torch.linspace(0.1, 10, 100).reshape(-1, 1).float()
    y_pred = model(x_test).numpy()

# 可视化结果
plt.plot(x_train, y_train, label='True')
plt.plot(x_test.numpy(), y_pred, label='Predicted')
plt.xlabel('x')
plt.ylabel('1/x')
plt.legend()
plt.show()